<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
  "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">


<html xmlns="http://www.w3.org/1999/xhtml">
  <head>
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
    
    <title>Writing your first Django app, part 5 &mdash; Django 1.7.8.dev20150401230226 documentation</title>
    
    <link rel="stylesheet" href="../_static/default.css" type="text/css" />
    <link rel="stylesheet" href="../_static/pygments.css" type="text/css" />
    
    <script type="text/javascript">
      var DOCUMENTATION_OPTIONS = {
        URL_ROOT:    '../',
        VERSION:     '1.7.8.dev20150401230226',
        COLLAPSE_INDEX: false,
        FILE_SUFFIX: '.html',
        HAS_SOURCE:  true
      };
    </script>
    <script type="text/javascript" src="../_static/jquery.js"></script>
    <script type="text/javascript" src="../_static/underscore.js"></script>
    <script type="text/javascript" src="../_static/doctools.js"></script>
    <link rel="top" title="Django 1.7.8.dev20150401230226 documentation" href="../index.html" />
    <link rel="up" title="Getting started" href="index.html" />
    <link rel="next" title="Writing your first Django app, part 6" href="tutorial06.html" />
    <link rel="prev" title="Writing your first Django app, part 4" href="tutorial04.html" />



 
<script type="text/javascript" src="../templatebuiltins.js"></script>
<script type="text/javascript">
(function($) {
    if (!django_template_builtins) {
       // templatebuiltins.js missing, do nothing.
       return;
    }
    $(document).ready(function() {
        // Hyperlink Django template tags and filters
        var base = "../ref/templates/builtins.html";
        if (base == "#") {
            // Special case for builtins.html itself
            base = "";
        }
        // Tags are keywords, class '.k'
        $("div.highlight\\-html\\+django span.k").each(function(i, elem) {
             var tagname = $(elem).text();
             if ($.inArray(tagname, django_template_builtins.ttags) != -1) {
                 var fragment = tagname.replace(/_/, '-');
                 $(elem).html("<a href='" + base + "#" + fragment + "'>" + tagname + "</a>");
             }
        });
        // Filters are functions, class '.nf'
        $("div.highlight\\-html\\+django span.nf").each(function(i, elem) {
             var filtername = $(elem).text();
             if ($.inArray(filtername, django_template_builtins.tfilters) != -1) {
                 var fragment = filtername.replace(/_/, '-');
                 $(elem).html("<a href='" + base + "#" + fragment + "'>" + filtername + "</a>");
             }
        });
    });
})(jQuery);
</script>


  </head>
  <body>

    <div class="document">
  <div id="custom-doc" class="yui-t6">
    <div id="hd">
      <h1><a href="../index.html">Django 1.7.8.dev20150401230226 documentation</a></h1>
      <div id="global-nav">
        <a title="Home page" href="../index.html">Home</a>  |
        <a title="Table of contents" href="../contents.html">Table of contents</a>  |
        <a title="Global index" href="../genindex.html">Index</a>  |
        <a title="Module index" href="../py-modindex.html">Modules</a>
      </div>
      <div class="nav">
    &laquo; <a href="tutorial04.html" title="Writing your first Django app, part 4">previous</a>
     |
    <a href="index.html" title="Getting started" accesskey="U">up</a>
   |
    <a href="tutorial06.html" title="Writing your first Django app, part 6">next</a> &raquo;</div>
    </div>

    <div id="bd">
      <div id="yui-main">
        <div class="yui-b">
          <div class="yui-g" id="intro-tutorial05">
            
  <div class="section" id="s-writing-your-first-django-app-part-5">
<span id="writing-your-first-django-app-part-5"></span><h1>Writing your first Django app, part 5<a class="headerlink" href="#writing-your-first-django-app-part-5" title="Permalink to this headline">¶</a></h1>
<p>This tutorial begins where <a class="reference internal" href="tutorial04.html"><em>Tutorial 4</em></a> left off.
We&#8217;ve built a Web-poll application, and we&#8217;ll now create some automated tests
for it.</p>
<div class="section" id="s-introducing-automated-testing">
<span id="introducing-automated-testing"></span><h2>Introducing automated testing<a class="headerlink" href="#introducing-automated-testing" title="Permalink to this headline">¶</a></h2>
<div class="section" id="s-what-are-automated-tests">
<span id="what-are-automated-tests"></span><h3>What are automated tests?<a class="headerlink" href="#what-are-automated-tests" title="Permalink to this headline">¶</a></h3>
<p>Tests are simple routines that check the operation of your code.</p>
<p>Testing operates at different levels. Some tests might apply to a tiny detail
(<em>does a particular model method return values as expected?</em>) while others
examine the overall operation of the software (<em>does a sequence of user inputs
on the site produce the desired result?</em>). That&#8217;s no different from the kind of
testing you did earlier in <a class="reference internal" href="tutorial01.html"><em>Tutorial 1</em></a>, using the
<a class="reference internal" href="../ref/django-admin.html#django-admin-shell"><tt class="xref std std-djadmin docutils literal"><span class="pre">shell</span></tt></a> to examine the behavior of a method, or running the
application and entering data to check how it behaves.</p>
<p>What&#8217;s different in <em>automated</em> tests is that the testing work is done for
you by the system. You create a set of tests once, and then as you make changes
to your app, you can check that your code still works as you originally
intended, without having to perform time consuming manual testing.</p>
</div>
<div class="section" id="s-why-you-need-to-create-tests">
<span id="why-you-need-to-create-tests"></span><h3>Why you need to create tests<a class="headerlink" href="#why-you-need-to-create-tests" title="Permalink to this headline">¶</a></h3>
<p>So why create tests, and why now?</p>
<p>You may feel that you have quite enough on your plate just learning
Python/Django, and having yet another thing to learn and do may seem
overwhelming and perhaps unnecessary. After all, our polls application is
working quite happily now; going through the trouble of creating automated
tests is not going to make it work any better. If creating the polls
application is the last bit of Django programming you will ever do, then true,
you don&#8217;t need to know how to create automated tests. But, if that&#8217;s not the
case, now is an excellent time to learn.</p>
<div class="section" id="s-tests-will-save-you-time">
<span id="tests-will-save-you-time"></span><h4>Tests will save you time<a class="headerlink" href="#tests-will-save-you-time" title="Permalink to this headline">¶</a></h4>
<p>Up to a certain point, &#8216;checking that it seems to work&#8217; will be a satisfactory
test. In a more sophisticated application, you might have dozens of complex
interactions between components.</p>
<p>A change in any of those components could have unexpected consequences on the
application&#8217;s behavior. Checking that it still &#8216;seems to work&#8217; could mean
running through your code&#8217;s functionality with twenty different variations of
your test data just to make sure you haven&#8217;t broken something - not a good use
of your time.</p>
<p>That&#8217;s especially true when automated tests could do this for you in seconds.
If something&#8217;s gone wrong, tests will also assist in identifying the code
that&#8217;s causing the unexpected behavior.</p>
<p>Sometimes it may seem a chore to tear yourself away from your productive,
creative programming work to face the unglamorous and unexciting business
of writing tests, particularly when you know your code is working properly.</p>
<p>However, the task of writing tests is a lot more fulfilling than spending hours
testing your application manually or trying to identify the cause of a
newly-introduced problem.</p>
</div>
<div class="section" id="s-tests-don-t-just-identify-problems-they-prevent-them">
<span id="tests-don-t-just-identify-problems-they-prevent-them"></span><h4>Tests don&#8217;t just identify problems, they prevent them<a class="headerlink" href="#tests-don-t-just-identify-problems-they-prevent-them" title="Permalink to this headline">¶</a></h4>
<p>It&#8217;s a mistake to think of tests merely as a negative aspect of development.</p>
<p>Without tests, the purpose or intended behavior of an application might be
rather opaque. Even when it&#8217;s your own code, you will sometimes find yourself
poking around in it trying to find out what exactly it&#8217;s doing.</p>
<p>Tests change that; they light up your code from the inside, and when something
goes wrong, they focus light on the part that has gone wrong - <em>even if you
hadn&#8217;t even realized it had gone wrong</em>.</p>
</div>
<div class="section" id="s-tests-make-your-code-more-attractive">
<span id="tests-make-your-code-more-attractive"></span><h4>Tests make your code more attractive<a class="headerlink" href="#tests-make-your-code-more-attractive" title="Permalink to this headline">¶</a></h4>
<p>You might have created a brilliant piece of software, but you will find that
many other developers will simply refuse to look at it because it lacks tests;
without tests, they won&#8217;t trust it. Jacob Kaplan-Moss, one of Django&#8217;s
original developers, says &#8220;Code without tests is broken by design.&#8221;</p>
<p>That other developers want to see tests in your software before they take it
seriously is yet another reason for you to start writing tests.</p>
</div>
<div class="section" id="s-tests-help-teams-work-together">
<span id="tests-help-teams-work-together"></span><h4>Tests help teams work together<a class="headerlink" href="#tests-help-teams-work-together" title="Permalink to this headline">¶</a></h4>
<p>The previous points are written from the point of view of a single developer
maintaining an application. Complex applications will be maintained by teams.
Tests guarantee that colleagues don&#8217;t inadvertently break your code (and that
you don&#8217;t break theirs without knowing). If you want to make a living as a
Django programmer, you must be good at writing tests!</p>
</div>
</div>
</div>
<div class="section" id="s-basic-testing-strategies">
<span id="basic-testing-strategies"></span><h2>Basic testing strategies<a class="headerlink" href="#basic-testing-strategies" title="Permalink to this headline">¶</a></h2>
<p>There are many ways to approach writing tests.</p>
<p>Some programmers follow a discipline called &#8220;<a class="reference external" href="http://en.wikipedia.org/wiki/Test-driven_development">test-driven development</a>&#8221;; they
actually write their tests before they write their code. This might seem
counter-intuitive, but in fact it&#8217;s similar to what most people will often do
anyway: they describe a problem, then create some code to solve it. Test-driven
development simply formalizes the problem in a Python test case.</p>
<p>More often, a newcomer to testing will create some code and later decide that
it should have some tests. Perhaps it would have been better to write some
tests earlier, but it&#8217;s never too late to get started.</p>
<p>Sometimes it&#8217;s difficult to figure out where to get started with writing tests.
If you have written several thousand lines of Python, choosing something to
test might not be easy. In such a case, it&#8217;s fruitful to write your first test
the next time you make a change, either when you add a new feature or fix a bug.</p>
<p>So let&#8217;s do that right away.</p>
</div>
<div class="section" id="s-writing-our-first-test">
<span id="writing-our-first-test"></span><h2>Writing our first test<a class="headerlink" href="#writing-our-first-test" title="Permalink to this headline">¶</a></h2>
<div class="section" id="s-we-identify-a-bug">
<span id="we-identify-a-bug"></span><h3>We identify a bug<a class="headerlink" href="#we-identify-a-bug" title="Permalink to this headline">¶</a></h3>
<p>Fortunately, there&#8217;s a little bug in the <tt class="docutils literal"><span class="pre">polls</span></tt> application for us to fix
right away: the <tt class="docutils literal"><span class="pre">Question.was_published_recently()</span></tt> method returns <tt class="docutils literal"><span class="pre">True</span></tt> if
the <tt class="docutils literal"><span class="pre">Question</span></tt> was published within the last day (which is correct) but also if
the <tt class="docutils literal"><span class="pre">Question</span></tt>’s <tt class="docutils literal"><span class="pre">pub_date</span></tt> field is in the future (which certainly isn&#8217;t).</p>
<p>You can see this in the Admin; create a question whose date lies in the future;
you&#8217;ll see that the <tt class="docutils literal"><span class="pre">Question</span></tt> change list claims it was published recently.</p>
<p>You can also see this using the <a class="reference internal" href="../ref/django-admin.html#django-admin-shell"><tt class="xref std std-djadmin docutils literal"><span class="pre">shell</span></tt></a>:</p>
<div class="highlight-python"><div class="highlight"><pre><span class="gp">&gt;&gt;&gt; </span><span class="kn">import</span> <span class="nn">datetime</span>
<span class="gp">&gt;&gt;&gt; </span><span class="kn">from</span> <span class="nn">django.utils</span> <span class="kn">import</span> <span class="n">timezone</span>
<span class="gp">&gt;&gt;&gt; </span><span class="kn">from</span> <span class="nn">polls.models</span> <span class="kn">import</span> <span class="n">Question</span>
<span class="gp">&gt;&gt;&gt; </span><span class="c"># create a Question instance with pub_date 30 days in the future</span>
<span class="gp">&gt;&gt;&gt; </span><span class="n">future_question</span> <span class="o">=</span> <span class="n">Question</span><span class="p">(</span><span class="n">pub_date</span><span class="o">=</span><span class="n">timezone</span><span class="o">.</span><span class="n">now</span><span class="p">()</span> <span class="o">+</span> <span class="n">datetime</span><span class="o">.</span><span class="n">timedelta</span><span class="p">(</span><span class="n">days</span><span class="o">=</span><span class="mi">30</span><span class="p">))</span>
<span class="gp">&gt;&gt;&gt; </span><span class="c"># was it published recently?</span>
<span class="gp">&gt;&gt;&gt; </span><span class="n">future_question</span><span class="o">.</span><span class="n">was_published_recently</span><span class="p">()</span>
<span class="go">True</span>
</pre></div>
</div>
<p>Since things in the future are not &#8216;recent&#8217;, this is clearly wrong.</p>
</div>
<div class="section" id="s-create-a-test-to-expose-the-bug">
<span id="create-a-test-to-expose-the-bug"></span><h3>Create a test to expose the bug<a class="headerlink" href="#create-a-test-to-expose-the-bug" title="Permalink to this headline">¶</a></h3>
<p>What we&#8217;ve just done in the <a class="reference internal" href="../ref/django-admin.html#django-admin-shell"><tt class="xref std std-djadmin docutils literal"><span class="pre">shell</span></tt></a> to test for the problem is exactly
what we can do in an automated test, so let&#8217;s turn that into an automated test.</p>
<p>A conventional place for an application&#8217;s tests is in the application&#8217;s
<tt class="docutils literal"><span class="pre">tests.py</span></tt> file; the testing system will automatically find tests in any file
whose name begins with <tt class="docutils literal"><span class="pre">test</span></tt>.</p>
<p>Put the following in the <tt class="docutils literal"><span class="pre">tests.py</span></tt> file in the <tt class="docutils literal"><span class="pre">polls</span></tt> application:</p>
<div class="highlight-python"><div class="snippet-filename">polls/tests.py</div>
<div class="highlight"><pre><span class="kn">import</span> <span class="nn">datetime</span>

<span class="kn">from</span> <span class="nn">django.utils</span> <span class="kn">import</span> <span class="n">timezone</span>
<span class="kn">from</span> <span class="nn">django.test</span> <span class="kn">import</span> <span class="n">TestCase</span>

<span class="kn">from</span> <span class="nn">polls.models</span> <span class="kn">import</span> <span class="n">Question</span>

<span class="k">class</span> <span class="nc">QuestionMethodTests</span><span class="p">(</span><span class="n">TestCase</span><span class="p">):</span>

    <span class="k">def</span> <span class="nf">test_was_published_recently_with_future_question</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
        <span class="sd">&quot;&quot;&quot;</span>
<span class="sd">        was_published_recently() should return False for questions whose</span>
<span class="sd">        pub_date is in the future.</span>
<span class="sd">        &quot;&quot;&quot;</span>
        <span class="n">time</span> <span class="o">=</span> <span class="n">timezone</span><span class="o">.</span><span class="n">now</span><span class="p">()</span> <span class="o">+</span> <span class="n">datetime</span><span class="o">.</span><span class="n">timedelta</span><span class="p">(</span><span class="n">days</span><span class="o">=</span><span class="mi">30</span><span class="p">)</span>
        <span class="n">future_question</span> <span class="o">=</span> <span class="n">Question</span><span class="p">(</span><span class="n">pub_date</span><span class="o">=</span><span class="n">time</span><span class="p">)</span>
        <span class="bp">self</span><span class="o">.</span><span class="n">assertEqual</span><span class="p">(</span><span class="n">future_question</span><span class="o">.</span><span class="n">was_published_recently</span><span class="p">(),</span> <span class="bp">False</span><span class="p">)</span>
</pre></div>
</div>
<p>What we have done here is created a <a class="reference internal" href="../topics/testing/tools.html#django.test.TestCase" title="django.test.TestCase"><tt class="xref py py-class docutils literal"><span class="pre">django.test.TestCase</span></tt></a> subclass
with a method that creates a <tt class="docutils literal"><span class="pre">Question</span></tt> instance with a <tt class="docutils literal"><span class="pre">pub_date</span></tt> in the
future. We then check the output of <tt class="docutils literal"><span class="pre">was_published_recently()</span></tt> - which
<em>ought</em> to be False.</p>
</div>
<div class="section" id="s-running-tests">
<span id="running-tests"></span><h3>Running tests<a class="headerlink" href="#running-tests" title="Permalink to this headline">¶</a></h3>
<p>In the terminal, we can run our test:</p>
<div class="highlight-python"><div class="highlight"><pre>$ python manage.py test polls
</pre></div>
</div>
<p>and you&#8217;ll see something like:</p>
<div class="highlight-python"><div class="highlight"><pre>Creating test database for alias &#39;default&#39;...
F
======================================================================
FAIL: test_was_published_recently_with_future_question (polls.tests.QuestionMethodTests)
----------------------------------------------------------------------
Traceback (most recent call last):
  File &quot;/path/to/mysite/polls/tests.py&quot;, line 16, in test_was_published_recently_with_future_question
    self.assertEqual(future_question.was_published_recently(), False)
AssertionError: True != False

----------------------------------------------------------------------
Ran 1 test in 0.001s

FAILED (failures=1)
Destroying test database for alias &#39;default&#39;...
</pre></div>
</div>
<p>What happened is this:</p>
<ul class="simple">
<li><tt class="docutils literal"><span class="pre">python</span> <span class="pre">manage.py</span> <span class="pre">test</span> <span class="pre">polls</span></tt> looked for tests in the <tt class="docutils literal"><span class="pre">polls</span></tt> application</li>
<li>it found a subclass of the <a class="reference internal" href="../topics/testing/tools.html#django.test.TestCase" title="django.test.TestCase"><tt class="xref py py-class docutils literal"><span class="pre">django.test.TestCase</span></tt></a> class</li>
<li>it created a special database for the purpose of testing</li>
<li>it looked for test methods - ones whose names begin with <tt class="docutils literal"><span class="pre">test</span></tt></li>
<li>in <tt class="docutils literal"><span class="pre">test_was_published_recently_with_future_question</span></tt> it created a <tt class="docutils literal"><span class="pre">Question</span></tt>
instance whose <tt class="docutils literal"><span class="pre">pub_date</span></tt> field is 30 days in the future</li>
<li>... and using the <tt class="docutils literal"><span class="pre">assertEqual()</span></tt> method, it discovered that its
<tt class="docutils literal"><span class="pre">was_published_recently()</span></tt> returns <tt class="docutils literal"><span class="pre">True</span></tt>, though we wanted it to return
<tt class="docutils literal"><span class="pre">False</span></tt></li>
</ul>
<p>The test informs us which test failed and even the line on which the failure
occurred.</p>
</div>
<div class="section" id="s-fixing-the-bug">
<span id="fixing-the-bug"></span><h3>Fixing the bug<a class="headerlink" href="#fixing-the-bug" title="Permalink to this headline">¶</a></h3>
<p>We already know what the problem is: <tt class="docutils literal"><span class="pre">Question.was_published_recently()</span></tt> should
return <tt class="docutils literal"><span class="pre">False</span></tt> if its <tt class="docutils literal"><span class="pre">pub_date</span></tt> is in the future. Amend the method in
<tt class="docutils literal"><span class="pre">models.py</span></tt>, so that it will only return <tt class="docutils literal"><span class="pre">True</span></tt> if the date is also in the
past:</p>
<div class="highlight-python"><div class="snippet-filename">polls/models.py</div>
<div class="highlight"><pre><span class="k">def</span> <span class="nf">was_published_recently</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
    <span class="n">now</span> <span class="o">=</span> <span class="n">timezone</span><span class="o">.</span><span class="n">now</span><span class="p">()</span>
    <span class="k">return</span> <span class="n">now</span> <span class="o">-</span> <span class="n">datetime</span><span class="o">.</span><span class="n">timedelta</span><span class="p">(</span><span class="n">days</span><span class="o">=</span><span class="mi">1</span><span class="p">)</span> <span class="o">&lt;=</span> <span class="bp">self</span><span class="o">.</span><span class="n">pub_date</span> <span class="o">&lt;=</span> <span class="n">now</span>
</pre></div>
</div>
<p>and run the test again:</p>
<div class="highlight-python"><div class="highlight"><pre>Creating test database for alias &#39;default&#39;...
.
----------------------------------------------------------------------
Ran 1 test in 0.001s

OK
Destroying test database for alias &#39;default&#39;...
</pre></div>
</div>
<p>After identifying a bug, we wrote a test that exposes it and corrected the bug
in the code so our test passes.</p>
<p>Many other things might go wrong with our application in the future, but we can
be sure that we won&#8217;t inadvertently reintroduce this bug, because simply
running the test will warn us immediately. We can consider this little portion
of the application pinned down safely forever.</p>
</div>
<div class="section" id="s-more-comprehensive-tests">
<span id="more-comprehensive-tests"></span><h3>More comprehensive tests<a class="headerlink" href="#more-comprehensive-tests" title="Permalink to this headline">¶</a></h3>
<p>While we&#8217;re here, we can further pin down the <tt class="docutils literal"><span class="pre">was_published_recently()</span></tt>
method; in fact, it would be positively embarrassing if in fixing one bug we had
introduced another.</p>
<p>Add two more test methods to the same class, to test the behavior of the method
more comprehensively:</p>
<div class="highlight-python"><div class="snippet-filename">polls/tests.py</div>
<div class="highlight"><pre><span class="k">def</span> <span class="nf">test_was_published_recently_with_old_question</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
    <span class="sd">&quot;&quot;&quot;</span>
<span class="sd">    was_published_recently() should return False for questions whose</span>
<span class="sd">    pub_date is older than 1 day.</span>
<span class="sd">    &quot;&quot;&quot;</span>
    <span class="n">time</span> <span class="o">=</span> <span class="n">timezone</span><span class="o">.</span><span class="n">now</span><span class="p">()</span> <span class="o">-</span> <span class="n">datetime</span><span class="o">.</span><span class="n">timedelta</span><span class="p">(</span><span class="n">days</span><span class="o">=</span><span class="mi">30</span><span class="p">)</span>
    <span class="n">old_question</span> <span class="o">=</span> <span class="n">Question</span><span class="p">(</span><span class="n">pub_date</span><span class="o">=</span><span class="n">time</span><span class="p">)</span>
    <span class="bp">self</span><span class="o">.</span><span class="n">assertEqual</span><span class="p">(</span><span class="n">old_question</span><span class="o">.</span><span class="n">was_published_recently</span><span class="p">(),</span> <span class="bp">False</span><span class="p">)</span>

<span class="k">def</span> <span class="nf">test_was_published_recently_with_recent_question</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
    <span class="sd">&quot;&quot;&quot;</span>
<span class="sd">    was_published_recently() should return True for questions whose</span>
<span class="sd">    pub_date is within the last day.</span>
<span class="sd">    &quot;&quot;&quot;</span>
    <span class="n">time</span> <span class="o">=</span> <span class="n">timezone</span><span class="o">.</span><span class="n">now</span><span class="p">()</span> <span class="o">-</span> <span class="n">datetime</span><span class="o">.</span><span class="n">timedelta</span><span class="p">(</span><span class="n">hours</span><span class="o">=</span><span class="mi">1</span><span class="p">)</span>
    <span class="n">recent_question</span> <span class="o">=</span> <span class="n">Question</span><span class="p">(</span><span class="n">pub_date</span><span class="o">=</span><span class="n">time</span><span class="p">)</span>
    <span class="bp">self</span><span class="o">.</span><span class="n">assertEqual</span><span class="p">(</span><span class="n">recent_question</span><span class="o">.</span><span class="n">was_published_recently</span><span class="p">(),</span> <span class="bp">True</span><span class="p">)</span>
</pre></div>
</div>
<p>And now we have three tests that confirm that <tt class="docutils literal"><span class="pre">Question.was_published_recently()</span></tt>
returns sensible values for past, recent, and future questions.</p>
<p>Again, <tt class="docutils literal"><span class="pre">polls</span></tt> is a simple application, but however complex it grows in the
future and whatever other code it interacts with, we now have some guarantee
that the method we have written tests for will behave in expected ways.</p>
</div>
</div>
<div class="section" id="s-test-a-view">
<span id="test-a-view"></span><h2>Test a view<a class="headerlink" href="#test-a-view" title="Permalink to this headline">¶</a></h2>
<p>The polls application is fairly undiscriminating: it will publish any question,
including ones whose <tt class="docutils literal"><span class="pre">pub_date</span></tt> field lies in the future. We should improve
this. Setting a <tt class="docutils literal"><span class="pre">pub_date</span></tt> in the future should mean that the Question is
published at that moment, but invisible until then.</p>
<div class="section" id="s-a-test-for-a-view">
<span id="a-test-for-a-view"></span><h3>A test for a view<a class="headerlink" href="#a-test-for-a-view" title="Permalink to this headline">¶</a></h3>
<p>When we fixed the bug above, we wrote the test first and then the code to fix
it. In fact that was a simple example of test-driven development, but it
doesn&#8217;t really matter in which order we do the work.</p>
<p>In our first test, we focused closely on the internal behavior of the code. For
this test, we want to check its behavior as it would be experienced by a user
through a web browser.</p>
<p>Before we try to fix anything, let&#8217;s have a look at the tools at our disposal.</p>
</div>
<div class="section" id="s-the-django-test-client">
<span id="the-django-test-client"></span><h3>The Django test client<a class="headerlink" href="#the-django-test-client" title="Permalink to this headline">¶</a></h3>
<p>Django provides a test <a class="reference internal" href="../topics/testing/tools.html#django.test.Client" title="django.test.Client"><tt class="xref py py-class docutils literal"><span class="pre">Client</span></tt></a> to simulate a user
interacting with the code at the view level.  We can use it in <tt class="docutils literal"><span class="pre">tests.py</span></tt>
or even in the <a class="reference internal" href="../ref/django-admin.html#django-admin-shell"><tt class="xref std std-djadmin docutils literal"><span class="pre">shell</span></tt></a>.</p>
<p>We will start again with the <a class="reference internal" href="../ref/django-admin.html#django-admin-shell"><tt class="xref std std-djadmin docutils literal"><span class="pre">shell</span></tt></a>, where we need to do a couple of
things that won&#8217;t be necessary in <tt class="docutils literal"><span class="pre">tests.py</span></tt>. The first is to set up the test
environment in the <a class="reference internal" href="../ref/django-admin.html#django-admin-shell"><tt class="xref std std-djadmin docutils literal"><span class="pre">shell</span></tt></a>:</p>
<div class="highlight-python"><div class="highlight"><pre><span class="gp">&gt;&gt;&gt; </span><span class="kn">from</span> <span class="nn">django.test.utils</span> <span class="kn">import</span> <span class="n">setup_test_environment</span>
<span class="gp">&gt;&gt;&gt; </span><span class="n">setup_test_environment</span><span class="p">()</span>
</pre></div>
</div>
<p><a class="reference internal" href="../topics/testing/advanced.html#django.test.utils.setup_test_environment" title="django.test.utils.setup_test_environment"><tt class="xref py py-meth docutils literal"><span class="pre">setup_test_environment()</span></tt></a> installs a template renderer
which will allow us to examine some additional attributes on responses such as
<tt class="docutils literal"><span class="pre">response.context</span></tt> that otherwise wouldn&#8217;t be available. Note that this
method <em>does not</em> setup a test database, so the following will be run against
the existing database and the output may differ slightly depending on what
questions you already created.</p>
<p>Next we need to import the test client class (later in <tt class="docutils literal"><span class="pre">tests.py</span></tt> we will use
the <a class="reference internal" href="../topics/testing/tools.html#django.test.TestCase" title="django.test.TestCase"><tt class="xref py py-class docutils literal"><span class="pre">django.test.TestCase</span></tt></a> class, which comes with its own client, so
this won&#8217;t be required):</p>
<div class="highlight-python"><div class="highlight"><pre><span class="gp">&gt;&gt;&gt; </span><span class="kn">from</span> <span class="nn">django.test</span> <span class="kn">import</span> <span class="n">Client</span>
<span class="gp">&gt;&gt;&gt; </span><span class="c"># create an instance of the client for our use</span>
<span class="gp">&gt;&gt;&gt; </span><span class="n">client</span> <span class="o">=</span> <span class="n">Client</span><span class="p">()</span>
</pre></div>
</div>
<p>With that ready, we can ask the client to do some work for us:</p>
<div class="highlight-python"><div class="highlight"><pre><span class="gp">&gt;&gt;&gt; </span><span class="c"># get a response from &#39;/&#39;</span>
<span class="gp">&gt;&gt;&gt; </span><span class="n">response</span> <span class="o">=</span> <span class="n">client</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s">&#39;/&#39;</span><span class="p">)</span>
<span class="gp">&gt;&gt;&gt; </span><span class="c"># we should expect a 404 from that address</span>
<span class="gp">&gt;&gt;&gt; </span><span class="n">response</span><span class="o">.</span><span class="n">status_code</span>
<span class="go">404</span>
<span class="gp">&gt;&gt;&gt; </span><span class="c"># on the other hand we should expect to find something at &#39;/polls/&#39;</span>
<span class="gp">&gt;&gt;&gt; </span><span class="c"># we&#39;ll use &#39;reverse()&#39; rather than a hardcoded URL</span>
<span class="gp">&gt;&gt;&gt; </span><span class="kn">from</span> <span class="nn">django.core.urlresolvers</span> <span class="kn">import</span> <span class="n">reverse</span>
<span class="gp">&gt;&gt;&gt; </span><span class="n">response</span> <span class="o">=</span> <span class="n">client</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="n">reverse</span><span class="p">(</span><span class="s">&#39;polls:index&#39;</span><span class="p">))</span>
<span class="gp">&gt;&gt;&gt; </span><span class="n">response</span><span class="o">.</span><span class="n">status_code</span>
<span class="go">200</span>
<span class="gp">&gt;&gt;&gt; </span><span class="n">response</span><span class="o">.</span><span class="n">content</span>
<span class="go">&#39;\n\n\n    &lt;p&gt;No polls are available.&lt;/p&gt;\n\n&#39;</span>
<span class="gp">&gt;&gt;&gt; </span><span class="c"># note - you might get unexpected results if your ``TIME_ZONE``</span>
<span class="gp">&gt;&gt;&gt; </span><span class="c"># in ``settings.py`` is not correct. If you need to change it,</span>
<span class="gp">&gt;&gt;&gt; </span><span class="c"># you will also need to restart your shell session</span>
<span class="gp">&gt;&gt;&gt; </span><span class="kn">from</span> <span class="nn">polls.models</span> <span class="kn">import</span> <span class="n">Question</span>
<span class="gp">&gt;&gt;&gt; </span><span class="kn">from</span> <span class="nn">django.utils</span> <span class="kn">import</span> <span class="n">timezone</span>
<span class="gp">&gt;&gt;&gt; </span><span class="c"># create a Question and save it</span>
<span class="gp">&gt;&gt;&gt; </span><span class="n">q</span> <span class="o">=</span> <span class="n">Question</span><span class="p">(</span><span class="n">question_text</span><span class="o">=</span><span class="s">&quot;Who is your favorite Beatle?&quot;</span><span class="p">,</span> <span class="n">pub_date</span><span class="o">=</span><span class="n">timezone</span><span class="o">.</span><span class="n">now</span><span class="p">())</span>
<span class="gp">&gt;&gt;&gt; </span><span class="n">q</span><span class="o">.</span><span class="n">save</span><span class="p">()</span>
<span class="gp">&gt;&gt;&gt; </span><span class="c"># check the response once again</span>
<span class="gp">&gt;&gt;&gt; </span><span class="n">response</span> <span class="o">=</span> <span class="n">client</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s">&#39;/polls/&#39;</span><span class="p">)</span>
<span class="gp">&gt;&gt;&gt; </span><span class="n">response</span><span class="o">.</span><span class="n">content</span>
<span class="go">&#39;\n\n\n    &lt;ul&gt;\n    \n        &lt;li&gt;&lt;a href=&quot;/polls/1/&quot;&gt;Who is your favorite Beatle?&lt;/a&gt;&lt;/li&gt;\n    \n    &lt;/ul&gt;\n\n&#39;</span>
<span class="gp">&gt;&gt;&gt; </span><span class="c"># If the following doesn&#39;t work, you probably omitted the call to</span>
<span class="gp">&gt;&gt;&gt; </span><span class="c"># setup_test_environment() described above</span>
<span class="gp">&gt;&gt;&gt; </span><span class="n">response</span><span class="o">.</span><span class="n">context</span><span class="p">[</span><span class="s">&#39;latest_question_list&#39;</span><span class="p">]</span>
<span class="go">[&lt;Question: Who is your favorite Beatle?&gt;]</span>
</pre></div>
</div>
</div>
<div class="section" id="s-improving-our-view">
<span id="improving-our-view"></span><h3>Improving our view<a class="headerlink" href="#improving-our-view" title="Permalink to this headline">¶</a></h3>
<p>The list of polls shows polls that aren&#8217;t published yet (i.e. those that have a
<tt class="docutils literal"><span class="pre">pub_date</span></tt> in the future). Let&#8217;s fix that.</p>
<p>In <a class="reference internal" href="tutorial04.html#tutorial04-amend-views"><em>Tutorial 4</em></a> we introduced a class-based view,
based on <a class="reference internal" href="../ref/class-based-views/generic-display.html#django.views.generic.list.ListView" title="django.views.generic.list.ListView"><tt class="xref py py-class docutils literal"><span class="pre">ListView</span></tt></a>:</p>
<div class="highlight-python"><div class="snippet-filename">polls/views.py</div>
<div class="highlight"><pre><span class="k">class</span> <span class="nc">IndexView</span><span class="p">(</span><span class="n">generic</span><span class="o">.</span><span class="n">ListView</span><span class="p">):</span>
    <span class="n">template_name</span> <span class="o">=</span> <span class="s">&#39;polls/index.html&#39;</span>
    <span class="n">context_object_name</span> <span class="o">=</span> <span class="s">&#39;latest_question_list&#39;</span>

    <span class="k">def</span> <span class="nf">get_queryset</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
        <span class="sd">&quot;&quot;&quot;Return the last five published questions.&quot;&quot;&quot;</span>
        <span class="k">return</span> <span class="n">Question</span><span class="o">.</span><span class="n">objects</span><span class="o">.</span><span class="n">order_by</span><span class="p">(</span><span class="s">&#39;-pub_date&#39;</span><span class="p">)[:</span><span class="mi">5</span><span class="p">]</span>
</pre></div>
</div>
<p><tt class="docutils literal"><span class="pre">response.context_data['latest_question_list']</span></tt> extracts the data this view
places into the context.</p>
<p>We need to amend the <tt class="docutils literal"><span class="pre">get_queryset</span></tt> method and change it so that it also
checks the date by comparing it with <tt class="docutils literal"><span class="pre">timezone.now()</span></tt>. First we need to add
an import:</p>
<div class="highlight-python"><div class="snippet-filename">polls/views.py</div>
<div class="highlight"><pre><span class="kn">from</span> <span class="nn">django.utils</span> <span class="kn">import</span> <span class="n">timezone</span>
</pre></div>
</div>
<p>and then we must amend the <tt class="docutils literal"><span class="pre">get_queryset</span></tt> method like so:</p>
<div class="highlight-python"><div class="snippet-filename">polls/views.py</div>
<div class="highlight"><pre><span class="k">def</span> <span class="nf">get_queryset</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
    <span class="sd">&quot;&quot;&quot;</span>
<span class="sd">    Return the last five published questions (not including those set to be</span>
<span class="sd">    published in the future).</span>
<span class="sd">    &quot;&quot;&quot;</span>
    <span class="k">return</span> <span class="n">Question</span><span class="o">.</span><span class="n">objects</span><span class="o">.</span><span class="n">filter</span><span class="p">(</span>
        <span class="n">pub_date__lte</span><span class="o">=</span><span class="n">timezone</span><span class="o">.</span><span class="n">now</span><span class="p">()</span>
    <span class="p">)</span><span class="o">.</span><span class="n">order_by</span><span class="p">(</span><span class="s">&#39;-pub_date&#39;</span><span class="p">)[:</span><span class="mi">5</span><span class="p">]</span>
</pre></div>
</div>
<p><tt class="docutils literal"><span class="pre">Question.objects.filter(pub_date__lte=timezone.now())</span></tt> returns a queryset
containing <tt class="docutils literal"><span class="pre">Question</span></tt>s whose <tt class="docutils literal"><span class="pre">pub_date</span></tt> is less than or equal to - that
is, earlier than or equal to - <tt class="docutils literal"><span class="pre">timezone.now</span></tt>.</p>
</div>
<div class="section" id="s-testing-our-new-view">
<span id="testing-our-new-view"></span><h3>Testing our new view<a class="headerlink" href="#testing-our-new-view" title="Permalink to this headline">¶</a></h3>
<p>Now you can satisfy yourself that this behaves as expected by firing up the
runserver, loading the site in your browser, creating <tt class="docutils literal"><span class="pre">Questions</span></tt> with dates
in the past and future, and checking that only those that have been published
are listed.  You don&#8217;t want to have to do that <em>every single time you make any
change that might affect this</em> - so let&#8217;s also create a test, based on our
<a class="reference internal" href="../ref/django-admin.html#django-admin-shell"><tt class="xref std std-djadmin docutils literal"><span class="pre">shell</span></tt></a> session above.</p>
<p>Add the following to <tt class="docutils literal"><span class="pre">polls/tests.py</span></tt>:</p>
<div class="highlight-python"><div class="snippet-filename">polls/tests.py</div>
<div class="highlight"><pre><span class="kn">from</span> <span class="nn">django.core.urlresolvers</span> <span class="kn">import</span> <span class="n">reverse</span>
</pre></div>
</div>
<p>and we&#8217;ll create a shortcut function to create questions as well as a new test
class:</p>
<div class="highlight-python"><div class="snippet-filename">polls/tests.py</div>
<div class="highlight"><pre><span class="k">def</span> <span class="nf">create_question</span><span class="p">(</span><span class="n">question_text</span><span class="p">,</span> <span class="n">days</span><span class="p">):</span>
    <span class="sd">&quot;&quot;&quot;</span>
<span class="sd">    Creates a question with the given `question_text` published the given</span>
<span class="sd">    number of `days` offset to now (negative for questions published</span>
<span class="sd">    in the past, positive for questions that have yet to be published).</span>
<span class="sd">    &quot;&quot;&quot;</span>
    <span class="n">time</span> <span class="o">=</span> <span class="n">timezone</span><span class="o">.</span><span class="n">now</span><span class="p">()</span> <span class="o">+</span> <span class="n">datetime</span><span class="o">.</span><span class="n">timedelta</span><span class="p">(</span><span class="n">days</span><span class="o">=</span><span class="n">days</span><span class="p">)</span>
    <span class="k">return</span> <span class="n">Question</span><span class="o">.</span><span class="n">objects</span><span class="o">.</span><span class="n">create</span><span class="p">(</span><span class="n">question_text</span><span class="o">=</span><span class="n">question_text</span><span class="p">,</span>
                                   <span class="n">pub_date</span><span class="o">=</span><span class="n">time</span><span class="p">)</span>


<span class="k">class</span> <span class="nc">QuestionViewTests</span><span class="p">(</span><span class="n">TestCase</span><span class="p">):</span>
    <span class="k">def</span> <span class="nf">test_index_view_with_no_questions</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
        <span class="sd">&quot;&quot;&quot;</span>
<span class="sd">        If no questions exist, an appropriate message should be displayed.</span>
<span class="sd">        &quot;&quot;&quot;</span>
        <span class="n">response</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">client</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="n">reverse</span><span class="p">(</span><span class="s">&#39;polls:index&#39;</span><span class="p">))</span>
        <span class="bp">self</span><span class="o">.</span><span class="n">assertEqual</span><span class="p">(</span><span class="n">response</span><span class="o">.</span><span class="n">status_code</span><span class="p">,</span> <span class="mi">200</span><span class="p">)</span>
        <span class="bp">self</span><span class="o">.</span><span class="n">assertContains</span><span class="p">(</span><span class="n">response</span><span class="p">,</span> <span class="s">&quot;No polls are available.&quot;</span><span class="p">)</span>
        <span class="bp">self</span><span class="o">.</span><span class="n">assertQuerysetEqual</span><span class="p">(</span><span class="n">response</span><span class="o">.</span><span class="n">context</span><span class="p">[</span><span class="s">&#39;latest_question_list&#39;</span><span class="p">],</span> <span class="p">[])</span>

    <span class="k">def</span> <span class="nf">test_index_view_with_a_past_question</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
        <span class="sd">&quot;&quot;&quot;</span>
<span class="sd">        Questions with a pub_date in the past should be displayed on the</span>
<span class="sd">        index page.</span>
<span class="sd">        &quot;&quot;&quot;</span>
        <span class="n">create_question</span><span class="p">(</span><span class="n">question_text</span><span class="o">=</span><span class="s">&quot;Past question.&quot;</span><span class="p">,</span> <span class="n">days</span><span class="o">=-</span><span class="mi">30</span><span class="p">)</span>
        <span class="n">response</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">client</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="n">reverse</span><span class="p">(</span><span class="s">&#39;polls:index&#39;</span><span class="p">))</span>
        <span class="bp">self</span><span class="o">.</span><span class="n">assertQuerysetEqual</span><span class="p">(</span>
            <span class="n">response</span><span class="o">.</span><span class="n">context</span><span class="p">[</span><span class="s">&#39;latest_question_list&#39;</span><span class="p">],</span>
            <span class="p">[</span><span class="s">&#39;&lt;Question: Past question.&gt;&#39;</span><span class="p">]</span>
        <span class="p">)</span>

    <span class="k">def</span> <span class="nf">test_index_view_with_a_future_question</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
        <span class="sd">&quot;&quot;&quot;</span>
<span class="sd">        Questions with a pub_date in the future should not be displayed on</span>
<span class="sd">        the index page.</span>
<span class="sd">        &quot;&quot;&quot;</span>
        <span class="n">create_question</span><span class="p">(</span><span class="n">question_text</span><span class="o">=</span><span class="s">&quot;Future question.&quot;</span><span class="p">,</span> <span class="n">days</span><span class="o">=</span><span class="mi">30</span><span class="p">)</span>
        <span class="n">response</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">client</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="n">reverse</span><span class="p">(</span><span class="s">&#39;polls:index&#39;</span><span class="p">))</span>
        <span class="bp">self</span><span class="o">.</span><span class="n">assertContains</span><span class="p">(</span><span class="n">response</span><span class="p">,</span> <span class="s">&quot;No polls are available.&quot;</span><span class="p">,</span>
                            <span class="n">status_code</span><span class="o">=</span><span class="mi">200</span><span class="p">)</span>
        <span class="bp">self</span><span class="o">.</span><span class="n">assertQuerysetEqual</span><span class="p">(</span><span class="n">response</span><span class="o">.</span><span class="n">context</span><span class="p">[</span><span class="s">&#39;latest_question_list&#39;</span><span class="p">],</span> <span class="p">[])</span>

    <span class="k">def</span> <span class="nf">test_index_view_with_future_question_and_past_question</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
        <span class="sd">&quot;&quot;&quot;</span>
<span class="sd">        Even if both past and future questions exist, only past questions</span>
<span class="sd">        should be displayed.</span>
<span class="sd">        &quot;&quot;&quot;</span>
        <span class="n">create_question</span><span class="p">(</span><span class="n">question_text</span><span class="o">=</span><span class="s">&quot;Past question.&quot;</span><span class="p">,</span> <span class="n">days</span><span class="o">=-</span><span class="mi">30</span><span class="p">)</span>
        <span class="n">create_question</span><span class="p">(</span><span class="n">question_text</span><span class="o">=</span><span class="s">&quot;Future question.&quot;</span><span class="p">,</span> <span class="n">days</span><span class="o">=</span><span class="mi">30</span><span class="p">)</span>
        <span class="n">response</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">client</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="n">reverse</span><span class="p">(</span><span class="s">&#39;polls:index&#39;</span><span class="p">))</span>
        <span class="bp">self</span><span class="o">.</span><span class="n">assertQuerysetEqual</span><span class="p">(</span>
            <span class="n">response</span><span class="o">.</span><span class="n">context</span><span class="p">[</span><span class="s">&#39;latest_question_list&#39;</span><span class="p">],</span>
            <span class="p">[</span><span class="s">&#39;&lt;Question: Past question.&gt;&#39;</span><span class="p">]</span>
        <span class="p">)</span>

    <span class="k">def</span> <span class="nf">test_index_view_with_two_past_questions</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
        <span class="sd">&quot;&quot;&quot;</span>
<span class="sd">        The questions index page may display multiple questions.</span>
<span class="sd">        &quot;&quot;&quot;</span>
        <span class="n">create_question</span><span class="p">(</span><span class="n">question_text</span><span class="o">=</span><span class="s">&quot;Past question 1.&quot;</span><span class="p">,</span> <span class="n">days</span><span class="o">=-</span><span class="mi">30</span><span class="p">)</span>
        <span class="n">create_question</span><span class="p">(</span><span class="n">question_text</span><span class="o">=</span><span class="s">&quot;Past question 2.&quot;</span><span class="p">,</span> <span class="n">days</span><span class="o">=-</span><span class="mi">5</span><span class="p">)</span>
        <span class="n">response</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">client</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="n">reverse</span><span class="p">(</span><span class="s">&#39;polls:index&#39;</span><span class="p">))</span>
        <span class="bp">self</span><span class="o">.</span><span class="n">assertQuerysetEqual</span><span class="p">(</span>
            <span class="n">response</span><span class="o">.</span><span class="n">context</span><span class="p">[</span><span class="s">&#39;latest_question_list&#39;</span><span class="p">],</span>
            <span class="p">[</span><span class="s">&#39;&lt;Question: Past question 2.&gt;&#39;</span><span class="p">,</span> <span class="s">&#39;&lt;Question: Past question 1.&gt;&#39;</span><span class="p">]</span>
        <span class="p">)</span>
</pre></div>
</div>
<p>Let&#8217;s look at some of these more closely.</p>
<p>First is a question shortcut function, <tt class="docutils literal"><span class="pre">create_question</span></tt>, to take some
repetition out of the process of creating questions.</p>
<p><tt class="docutils literal"><span class="pre">test_index_view_with_no_questions</span></tt> doesn&#8217;t create any questions, but checks
the message: &#8220;No polls are available.&#8221; and verifies the <tt class="docutils literal"><span class="pre">latest_question_list</span></tt>
is empty. Note that the <a class="reference internal" href="../topics/testing/tools.html#django.test.TestCase" title="django.test.TestCase"><tt class="xref py py-class docutils literal"><span class="pre">django.test.TestCase</span></tt></a> class provides some
additional assertion methods. In these examples, we use
<a class="reference internal" href="../topics/testing/tools.html#django.test.SimpleTestCase.assertContains" title="django.test.SimpleTestCase.assertContains"><tt class="xref py py-meth docutils literal"><span class="pre">assertContains()</span></tt></a> and
<a class="reference internal" href="../topics/testing/tools.html#django.test.TransactionTestCase.assertQuerysetEqual" title="django.test.TransactionTestCase.assertQuerysetEqual"><tt class="xref py py-meth docutils literal"><span class="pre">assertQuerysetEqual()</span></tt></a>.</p>
<p>In <tt class="docutils literal"><span class="pre">test_index_view_with_a_past_question</span></tt>, we create a question and verify that it
appears in the list.</p>
<p>In <tt class="docutils literal"><span class="pre">test_index_view_with_a_future_question</span></tt>, we create a question with a
<tt class="docutils literal"><span class="pre">pub_date</span></tt> in the future. The database is reset for each test method, so the
first question is no longer there, and so again the index shouldn&#8217;t have any
questions in it.</p>
<p>And so on. In effect, we are using the tests to tell a story of admin input
and user experience on the site, and checking that at every state and for every
new change in the state of the system, the expected results are published.</p>
</div>
<div class="section" id="s-testing-the-detailview">
<span id="testing-the-detailview"></span><h3>Testing the <tt class="docutils literal"><span class="pre">DetailView</span></tt><a class="headerlink" href="#testing-the-detailview" title="Permalink to this headline">¶</a></h3>
<p>What we have works well; however, even though future questions don&#8217;t appear in
the <em>index</em>, users can still reach them if they know or guess the right URL. So
we need to add a similar  constraint to <tt class="docutils literal"><span class="pre">DetailView</span></tt>:</p>
<div class="highlight-python"><div class="snippet-filename">polls/views.py</div>
<div class="highlight"><pre><span class="k">class</span> <span class="nc">DetailView</span><span class="p">(</span><span class="n">generic</span><span class="o">.</span><span class="n">DetailView</span><span class="p">):</span>
    <span class="o">...</span>
    <span class="k">def</span> <span class="nf">get_queryset</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
        <span class="sd">&quot;&quot;&quot;</span>
<span class="sd">        Excludes any questions that aren&#39;t published yet.</span>
<span class="sd">        &quot;&quot;&quot;</span>
        <span class="k">return</span> <span class="n">Question</span><span class="o">.</span><span class="n">objects</span><span class="o">.</span><span class="n">filter</span><span class="p">(</span><span class="n">pub_date__lte</span><span class="o">=</span><span class="n">timezone</span><span class="o">.</span><span class="n">now</span><span class="p">())</span>
</pre></div>
</div>
<p>And of course, we will add some tests, to check that a <tt class="docutils literal"><span class="pre">Question</span></tt> whose
<tt class="docutils literal"><span class="pre">pub_date</span></tt> is in the past can be displayed, and that one with a <tt class="docutils literal"><span class="pre">pub_date</span></tt>
in the future is not:</p>
<div class="highlight-python"><div class="snippet-filename">polls/tests.py</div>
<div class="highlight"><pre><span class="k">class</span> <span class="nc">QuestionIndexDetailTests</span><span class="p">(</span><span class="n">TestCase</span><span class="p">):</span>
    <span class="k">def</span> <span class="nf">test_detail_view_with_a_future_question</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
        <span class="sd">&quot;&quot;&quot;</span>
<span class="sd">        The detail view of a question with a pub_date in the future should</span>
<span class="sd">        return a 404 not found.</span>
<span class="sd">        &quot;&quot;&quot;</span>
        <span class="n">future_question</span> <span class="o">=</span> <span class="n">create_question</span><span class="p">(</span><span class="n">question_text</span><span class="o">=</span><span class="s">&#39;Future question.&#39;</span><span class="p">,</span>
                                          <span class="n">days</span><span class="o">=</span><span class="mi">5</span><span class="p">)</span>
        <span class="n">response</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">client</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="n">reverse</span><span class="p">(</span><span class="s">&#39;polls:detail&#39;</span><span class="p">,</span>
                                   <span class="n">args</span><span class="o">=</span><span class="p">(</span><span class="n">future_question</span><span class="o">.</span><span class="n">id</span><span class="p">,)))</span>
        <span class="bp">self</span><span class="o">.</span><span class="n">assertEqual</span><span class="p">(</span><span class="n">response</span><span class="o">.</span><span class="n">status_code</span><span class="p">,</span> <span class="mi">404</span><span class="p">)</span>

    <span class="k">def</span> <span class="nf">test_detail_view_with_a_past_question</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
        <span class="sd">&quot;&quot;&quot;</span>
<span class="sd">        The detail view of a question with a pub_date in the past should</span>
<span class="sd">        display the question&#39;s text.</span>
<span class="sd">        &quot;&quot;&quot;</span>
        <span class="n">past_question</span> <span class="o">=</span> <span class="n">create_question</span><span class="p">(</span><span class="n">question_text</span><span class="o">=</span><span class="s">&#39;Past Question.&#39;</span><span class="p">,</span>
                                        <span class="n">days</span><span class="o">=-</span><span class="mi">5</span><span class="p">)</span>
        <span class="n">response</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">client</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="n">reverse</span><span class="p">(</span><span class="s">&#39;polls:detail&#39;</span><span class="p">,</span>
                                   <span class="n">args</span><span class="o">=</span><span class="p">(</span><span class="n">past_question</span><span class="o">.</span><span class="n">id</span><span class="p">,)))</span>
        <span class="bp">self</span><span class="o">.</span><span class="n">assertContains</span><span class="p">(</span><span class="n">response</span><span class="p">,</span> <span class="n">past_question</span><span class="o">.</span><span class="n">question_text</span><span class="p">,</span>
                            <span class="n">status_code</span><span class="o">=</span><span class="mi">200</span><span class="p">)</span>
</pre></div>
</div>
</div>
<div class="section" id="s-ideas-for-more-tests">
<span id="ideas-for-more-tests"></span><h3>Ideas for more tests<a class="headerlink" href="#ideas-for-more-tests" title="Permalink to this headline">¶</a></h3>
<p>We ought to add a similar <tt class="docutils literal"><span class="pre">get_queryset</span></tt> method to <tt class="docutils literal"><span class="pre">ResultsView</span></tt> and
create a new test class for that view. It&#8217;ll be very similar to what we have
just created; in fact there will be a lot of repetition.</p>
<p>We could also improve our application in other ways, adding tests along the
way. For example, it&#8217;s silly that <tt class="docutils literal"><span class="pre">Questions</span></tt> can be published on the site
that have no <tt class="docutils literal"><span class="pre">Choices</span></tt>. So, our views could check for this, and exclude such
<tt class="docutils literal"><span class="pre">Questions</span></tt>. Our tests would create a <tt class="docutils literal"><span class="pre">Question</span></tt> without <tt class="docutils literal"><span class="pre">Choices</span></tt> and
then test that it&#8217;s not published, as well as create a similar <tt class="docutils literal"><span class="pre">Question</span></tt>
<em>with</em> <tt class="docutils literal"><span class="pre">Choices</span></tt>, and test that it <em>is</em> published.</p>
<p>Perhaps logged-in admin users should be allowed to see unpublished
<tt class="docutils literal"><span class="pre">Questions</span></tt>, but not ordinary visitors. Again: whatever needs to be added to
the software to accomplish this should be accompanied by a test, whether you
write the test first and then make the code pass the test, or work out the
logic in your code first and then write a test to prove it.</p>
<p>At a certain point you are bound to look at your tests and wonder whether your
code is suffering from test bloat, which brings us to:</p>
</div>
</div>
<div class="section" id="s-when-testing-more-is-better">
<span id="when-testing-more-is-better"></span><h2>When testing, more is better<a class="headerlink" href="#when-testing-more-is-better" title="Permalink to this headline">¶</a></h2>
<p>It might seem that our tests are growing out of control. At this rate there will
soon be more code in our tests than in our application, and the repetition
is unaesthetic, compared to the elegant conciseness of the rest of our code.</p>
<p><strong>It doesn&#8217;t matter</strong>. Let them grow. For the most part, you can write a test
once and then forget about it. It will continue performing its useful function
as you continue to develop your program.</p>
<p>Sometimes tests will need to be updated. Suppose that we amend our views so that
only <tt class="docutils literal"><span class="pre">Questions</span></tt> with <tt class="docutils literal"><span class="pre">Choices</span></tt> are published. In that case, many of our
existing tests will fail - <em>telling us exactly which tests need to be amended to
bring them up to date</em>, so to that extent tests help look after themselves.</p>
<p>At worst, as you continue developing, you might find that you have some tests
that are now redundant. Even that&#8217;s not a problem; in testing redundancy is
a <em>good</em> thing.</p>
<p>As long as your tests are sensibly arranged, they won&#8217;t become unmanageable.
Good rules-of-thumb include having:</p>
<ul class="simple">
<li>a separate <tt class="docutils literal"><span class="pre">TestClass</span></tt> for each model or view</li>
<li>a separate test method for each set of conditions you want to test</li>
<li>test method names that describe their function</li>
</ul>
</div>
<div class="section" id="s-further-testing">
<span id="further-testing"></span><h2>Further testing<a class="headerlink" href="#further-testing" title="Permalink to this headline">¶</a></h2>
<p>This tutorial only introduces some of the basics of testing. There&#8217;s a great
deal more you can do, and a number of very useful tools at your disposal to
achieve some very clever things.</p>
<p>For example, while our tests here have covered some of the internal logic of a
model and the way our views publish information, you can use an &#8220;in-browser&#8221;
framework such as <a class="reference external" href="http://seleniumhq.org/">Selenium</a> to test the way your HTML actually renders in a
browser. These tools allow you to check not just the behavior of your Django
code, but also, for example, of your JavaScript. It&#8217;s quite something to see
the tests launch a browser, and start interacting with your site, as if a human
being were driving it! Django includes <a class="reference internal" href="../topics/testing/tools.html#django.test.LiveServerTestCase" title="django.test.LiveServerTestCase"><tt class="xref py py-class docutils literal"><span class="pre">LiveServerTestCase</span></tt></a>
to facilitate integration with tools like Selenium.</p>
<p>If you have a complex application, you may want to run tests automatically
with every commit for the purposes of <a class="reference external" href="http://en.wikipedia.org/wiki/Continuous_integration">continuous integration</a>, so that
quality control is itself - at least partially - automated.</p>
<p>A good way to spot untested parts of your application is to check code
coverage. This also helps identify fragile or even dead code. If you can&#8217;t test
a piece of code, it usually means that code should be refactored or removed.
Coverage will help to identify dead code. See
<a class="reference internal" href="../topics/testing/advanced.html#topics-testing-code-coverage"><em>Integration with coverage.py</em></a> for details.</p>
<p><a class="reference internal" href="../topics/testing/index.html"><em>Testing in Django</em></a> has comprehensive
information about testing.</p>
</div>
<div class="section" id="s-what-s-next">
<span id="what-s-next"></span><h2>What&#8217;s next?<a class="headerlink" href="#what-s-next" title="Permalink to this headline">¶</a></h2>
<p>For full details on testing, see <a class="reference internal" href="../topics/testing/index.html"><em>Testing in Django</em></a>.</p>
<p>When you&#8217;re comfortable with testing Django views, read
<a class="reference internal" href="tutorial06.html"><em>part 6 of this tutorial</em></a> to learn about
static files management.</p>
</div>
</div>


          </div>
        </div>
      </div>
      
        
          <div class="yui-b" id="sidebar">
            
      <div class="sphinxsidebar">
        <div class="sphinxsidebarwrapper">
  <h3><a href="../contents.html">Table Of Contents</a></h3>
  <ul>
<li><a class="reference internal" href="#">Writing your first Django app, part 5</a><ul>
<li><a class="reference internal" href="#introducing-automated-testing">Introducing automated testing</a><ul>
<li><a class="reference internal" href="#what-are-automated-tests">What are automated tests?</a></li>
<li><a class="reference internal" href="#why-you-need-to-create-tests">Why you need to create tests</a><ul>
<li><a class="reference internal" href="#tests-will-save-you-time">Tests will save you time</a></li>
<li><a class="reference internal" href="#tests-don-t-just-identify-problems-they-prevent-them">Tests don&#8217;t just identify problems, they prevent them</a></li>
<li><a class="reference internal" href="#tests-make-your-code-more-attractive">Tests make your code more attractive</a></li>
<li><a class="reference internal" href="#tests-help-teams-work-together">Tests help teams work together</a></li>
</ul>
</li>
</ul>
</li>
<li><a class="reference internal" href="#basic-testing-strategies">Basic testing strategies</a></li>
<li><a class="reference internal" href="#writing-our-first-test">Writing our first test</a><ul>
<li><a class="reference internal" href="#we-identify-a-bug">We identify a bug</a></li>
<li><a class="reference internal" href="#create-a-test-to-expose-the-bug">Create a test to expose the bug</a></li>
<li><a class="reference internal" href="#running-tests">Running tests</a></li>
<li><a class="reference internal" href="#fixing-the-bug">Fixing the bug</a></li>
<li><a class="reference internal" href="#more-comprehensive-tests">More comprehensive tests</a></li>
</ul>
</li>
<li><a class="reference internal" href="#test-a-view">Test a view</a><ul>
<li><a class="reference internal" href="#a-test-for-a-view">A test for a view</a></li>
<li><a class="reference internal" href="#the-django-test-client">The Django test client</a></li>
<li><a class="reference internal" href="#improving-our-view">Improving our view</a></li>
<li><a class="reference internal" href="#testing-our-new-view">Testing our new view</a></li>
<li><a class="reference internal" href="#testing-the-detailview">Testing the <tt class="docutils literal"><span class="pre">DetailView</span></tt></a></li>
<li><a class="reference internal" href="#ideas-for-more-tests">Ideas for more tests</a></li>
</ul>
</li>
<li><a class="reference internal" href="#when-testing-more-is-better">When testing, more is better</a></li>
<li><a class="reference internal" href="#further-testing">Further testing</a></li>
<li><a class="reference internal" href="#what-s-next">What&#8217;s next?</a></li>
</ul>
</li>
</ul>

  <h3>Browse</h3>
  <ul>
    
      <li>Prev: <a href="tutorial04.html">Writing your first Django app, part 4</a></li>
    
    
      <li>Next: <a href="tutorial06.html">Writing your first Django app, part 6</a></li>
    
  </ul>
  <h3>You are here:</h3>
  <ul>
      <li>
        <a href="../index.html">Django 1.7.8.dev20150401230226 documentation</a>
        
          <ul><li><a href="index.html">Getting started</a>
        
        <ul><li>Writing your first Django app, part 5</li></ul>
        </li></ul>
      </li>
  </ul>

  <h3>This Page</h3>
  <ul class="this-page-menu">
    <li><a href="../_sources/intro/tutorial05.txt"
           rel="nofollow">Show Source</a></li>
  </ul>
<div id="searchbox" style="display: none">
  <h3>Quick search</h3>
    <form class="search" action="../search.html" method="get">
      <input type="text" name="q" />
      <input type="submit" value="Go" />
      <input type="hidden" name="check_keywords" value="yes" />
      <input type="hidden" name="area" value="default" />
    </form>
    <p class="searchtip" style="font-size: 90%">
    Enter search terms or a module, class or function name.
    </p>
</div>
<script type="text/javascript">$('#searchbox').show(0);</script>
        </div>
      </div>
              <h3>Last update:</h3>
              <p class="topless">Apr 02, 2015</p>
          </div>
        
      
    </div>

    <div id="ft">
      <div class="nav">
    &laquo; <a href="tutorial04.html" title="Writing your first Django app, part 4">previous</a>
     |
    <a href="index.html" title="Getting started" accesskey="U">up</a>
   |
    <a href="tutorial06.html" title="Writing your first Django app, part 6">next</a> &raquo;</div>
    </div>
  </div>

      <div class="clearer"></div>
    </div>
  </body>
</html>